use std::time::Duration;
use std::sync::Arc;
use std::any::Any;
use async_trait::async_trait;
use tracing::{info, debug, warn, span, Level};

use protoactor_rs::actor::{Actor, ActorContext, ActorError, DefaultActorContext, PID, Props, SystemMessage};
use protoactor_rs::middleware::{LoggingMiddleware, SenderMiddleware, ReceiverMiddleware, Sender, Receiver, SyncMessage, to_sync_message};
use protoactor_rs::ActorSystem;
use protoactor_rs::logging;

// Custom middleware that tracks message timing
#[derive(Debug, Clone)]
struct TimingMiddleware {
    name: String,
}

impl TimingMiddleware {
    fn new(name: impl Into<String>) -> Self {
        Self { name: name.into() }
    }
}

#[async_trait]
impl SenderMiddleware for TimingMiddleware {
    async fn send(&self, next: Arc<dyn Sender>, target: PID, message: SyncMessage) -> Result<(), ActorError> {
        let span = span!(Level::DEBUG, "middleware_send", name = self.name);
        let _enter = span.enter();
        
        let start = std::time::Instant::now();
        let result = next.send(target, message).await;
        let elapsed = start.elapsed();
        
        info!(middleware = self.name, elapsed_ms = elapsed.as_millis(), "Message sent");
        result
    }
    
    async fn send_system(&self, next: Arc<dyn Sender>, target: PID, message: SystemMessage) -> Result<(), ActorError> {
        let span = span!(Level::DEBUG, "middleware_send_system", name = self.name);
        let _enter = span.enter();
        
        let start = std::time::Instant::now();
        let result = next.send_system(target, message).await;
        let elapsed = start.elapsed();
        
        info!(middleware = self.name, elapsed_ms = elapsed.as_millis(), "System message sent");
        result
    }
}

#[async_trait]
impl ReceiverMiddleware for TimingMiddleware {
    async fn receive(&self, next: Arc<dyn Receiver>, context: &mut DefaultActorContext, message: SyncMessage) -> Result<(), ActorError> {
        let span = span!(Level::DEBUG, "middleware_receive", name = self.name);
        let _enter = span.enter();
        
        let start = std::time::Instant::now();
        let result = next.receive(context, message).await;
        let elapsed = start.elapsed();
        
        info!(middleware = self.name, elapsed_ms = elapsed.as_millis(), "Message processed");
        result
    }
    
    async fn receive_system(&self, next: Arc<dyn Receiver>, context: &mut DefaultActorContext, message: SystemMessage) -> Result<(), ActorError> {
        let span = span!(Level::DEBUG, "middleware_receive_system", name = self.name);
        let _enter = span.enter();
        
        let start = std::time::Instant::now();
        let result = next.receive_system(context, message).await;
        let elapsed = start.elapsed();
        
        info!(middleware = self.name, elapsed_ms = elapsed.as_millis(), "System message processed");
        result
    }
}

// Define a simple message
#[derive(Debug)]
struct Hello {
    name: String,
}

// Define a simple response
#[derive(Debug, Clone)]
struct HelloResponse {
    message: String,
}

// Define a simple actor
#[derive(Debug)]
struct GreeterActor;

#[async_trait]
impl Actor for GreeterActor {
    type Context = DefaultActorContext;
    
    async fn receive(&self, ctx: &mut Self::Context, msg: Box<dyn Any + Send>) -> Result<(), ActorError> {
        if let Ok(hello) = msg.downcast::<Hello>() {
            info!(name = hello.name, "Received Hello message");
            
            // Simulate some work
            tokio::time::sleep(Duration::from_millis(50)).await;
            
            // Create a response
            let response = HelloResponse {
                message: format!("Hello, {}!", hello.name),
            };
            
            // Respond to the sender
            ctx.respond(response);
            debug!("Sent response to sender");
        } else {
            warn!("Received unknown message");
        }
        
        Ok(())
    }
    
    async fn started(&self, _ctx: &mut Self::Context) -> Result<(), ActorError> {
        info!("GreeterActor started");
        Ok(())
    }
    
    async fn stopping(&self, _ctx: &mut Self::Context) -> Result<(), ActorError> {
        info!("GreeterActor stopping");
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    logging::init_global_logger(
        Some(tracing::Level::DEBUG),
        Some("middleware_example=info"),
    )?;
    
    // Create an actor system
    let system = ActorSystem::new()?;
    
    // Register middleware (in a real system, this would be configured in the ActorSystem)
    let sender_middlewares: Vec<Arc<dyn SenderMiddleware>> = vec![
        Arc::new(LoggingMiddleware::new("LoggingSender")),
        Arc::new(TimingMiddleware::new("TimingSender")),
    ];
    
    let receiver_middlewares: Vec<Arc<dyn ReceiverMiddleware>> = vec![
        Arc::new(LoggingMiddleware::new("LoggingReceiver")),
        Arc::new(TimingMiddleware::new("TimingReceiver")),
    ];
    
    // Create props for the actor
    let props = Props::from_producer(|| GreeterActor);
    
    // In a real system, the middleware would be attached to the props
    // and automatically used when spawning the actor
    
    // Spawn the actor
    let pid = system.spawn::<GreeterActor>(props).await?;
    
    info!(pid = %pid, "Actor spawned");
    
    // Send a message to the actor
    let message = Hello {
        name: "World".to_string(),
    };
    
    // In a real system, the sender middleware would automatically be used here
    system.send(&pid, message).await?;
    
    // Wait a bit for the message to be processed
    tokio::time::sleep(Duration::from_millis(100)).await;
    
    // Stop the actor
    system.stop(&pid).await?;
    
    // Wait a bit for the actor to stop
    tokio::time::sleep(Duration::from_millis(100)).await;
    
    info!("Example completed successfully");
    
    Ok(())
} 